package com.liinxin.flac_management.utils;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.file.FileNameUtil;
import cn.hutool.core.util.StrUtil;
import org.jaudiotagger.audio.AudioFile;
import org.jaudiotagger.audio.AudioFileIO;
import org.jaudiotagger.tag.FieldKey;
import org.jaudiotagger.tag.Tag;
import org.jaudiotagger.tag.datatype.Artwork;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

public class SongManage {
    /**
     * 获取音乐的扩展名
     *
     * @param songFile
     * @return
     */
    public static String getSongExtName(File songFile) {
        // 判断是否为音频
        if (isSong(songFile)) {
            // 确定为音频, 输出扩展名
            return FileNameUtil.getSuffix(songFile.getPath());
        } else {
            // 不为音频
            return null;
        }
    }

    /**
     * 判断是否为歌曲
     *
     * @param songFile
     * @return
     */
    public static boolean isSong(File songFile) {
        String mimeType = FileUtil.getMimeType(songFile.getPath());
        boolean isAudioFile = StrUtil.isNotBlank(mimeType) && mimeType.startsWith("audio/");
        return isAudioFile;
    }


    /**
     * 根据传入的wav文件, 转换为flac
     *
     * @param wavFile
     */
    public static void fileToFlac(File wavFile) {
        // 指定WAV文件路径
        // File wavFile = FileUtil.file("D:\\test\\asmr\\王小美\\阿莫斯\\new\\1日目_囁き最小限ゆっ…くり耳かき.wav");

        // 获取先前路径
        String prePath = FileManage.getPrePath(wavFile.getPath());
        // 获取文件名
        String mainName = FileNameUtil.mainName(wavFile.getPath());

        // 指定FLAC文件路径
        File flacFile = FileUtil.file(prePath + mainName + ".flac");

        // 构建FFmpeg命令
        String command = String.format("ffmpeg -i %s -acodec flac %s", wavFile.getAbsolutePath(), flacFile.getAbsolutePath());

        // 使用ProcessBuilder执行命令
        try {
            ProcessBuilder processBuilder = new ProcessBuilder(command.split(" "));
            processBuilder.directory(FileUtil.file(".")); // 设置当前目录
            Process process = processBuilder.start();

            // 等待FFmpeg命令执行完毕
            int exitCode = process.waitFor();
            if (exitCode == 0) {
                System.out.println("文件转换成功");
            } else {
                System.out.println("文件转换失败");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 根据传入的wav文件集合转换为flac格式, 单线程
     *
     * @param wavList
     */
    /*public static void listToFlac(List<File> wavList) {
        // 遍历集合
        for (int i = 0; i < wavList.size(); i++) {
            File wavFile = wavList.get(i);

            // 获取先前路径
            String prePath = FileManage.getPrePath(wavFile.getPath());
            // 获取文件名
            String mainName = FileNameUtil.mainName(wavFile.getPath());

            // 指定FLAC文件路径
            File flacFile = FileUtil.file(prePath + mainName + ".flac");

            // 构建FFmpeg命令
            String command = String.format("ffmpeg -i %s -acodec flac %s", wavFile.getAbsolutePath(), flacFile.getAbsolutePath());

            // 使用ProcessBuilder执行命令
            try {
                ProcessBuilder processBuilder = new ProcessBuilder(command.split(" "));
                processBuilder.directory(FileUtil.file(".")); // 设置当前目录
                Process process = processBuilder.start();

                // 等待FFmpeg命令执行完毕
                int exitCode = process.waitFor();
                if (exitCode == 0) {
                    System.out.println("文件转换成功");
                } else {
                    System.out.println("文件转换失败");
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }*/

    /**
     * 多线程 转换文件处理
     *
     * @param wavList
     */
    public static List<File> listToFlacByThreaded(List<File> wavList) {
        ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());

        List<File> flacFiles = new ArrayList<>();

        for (File wavFile : wavList) {
            final File flacFile = FileUtil.file(FileManage.getPrePath(wavFile.getPath()) + FileNameUtil.mainName(wavFile.getPath()) + ".flac");
            executorService.submit(() -> {
                String command = String.format("ffmpeg -i %s -acodec flac %s", wavFile.getAbsolutePath(), flacFile.getAbsolutePath());

                try {
                    ProcessBuilder processBuilder = new ProcessBuilder(command.split(" "));
                    processBuilder.directory(FileUtil.file("."));
                    Process process = processBuilder.start();

                    int exitCode = process.waitFor();
                    if (exitCode == 0) {
                        flacFiles.add(flacFile);
                        System.out.println("文件转换成功：" + flacFile.getAbsolutePath());
                    } else {
                        System.out.println("文件转换失败：" + flacFile.getAbsolutePath());
                    }
                } catch (IOException | InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }

        executorService.shutdown();

        try {
            executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        return flacFiles;
    }

    /**
     * 自定义线程 歌曲转换处理
     *
     * @param wavList
     * @param threadCount
     */
    public static List<File> listToFlacByThreaded(List<File> wavList, int threadCount) throws IOException, InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(threadCount);

        List<File> flacFiles = new ArrayList<>();

        for (File wavFile : wavList) {
            final File flacFile = FileUtil.file(FileManage.getPrePath(wavFile.getPath()) + FileNameUtil.mainName(wavFile.getPath()) + ".flac");
            executorService.submit(() -> {
                String command = String.format("ffmpeg -i %s -acodec flac %s", wavFile.getAbsolutePath(), flacFile.getAbsolutePath());

                try {
                    ProcessBuilder processBuilder = new ProcessBuilder(command.split(" "));
                    processBuilder.directory(FileUtil.file("."));
                    Process process = processBuilder.start();
                    System.out.println("文件卡在这里了, ffmpeg");
                    int exitCode = process.waitFor();
                    if (exitCode == 0) {
                        flacFiles.add(flacFile);
                        System.out.println("文件转换成功：" + flacFile.getAbsolutePath());
                    } else {
                        System.out.println("文件转换失败：" + flacFile.getAbsolutePath());
                    }
                } catch (IOException | InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }

        executorService.shutdown();
        try {
            executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        return flacFiles;
    }


    /**
     * 设置歌曲图片封面
     *
     * @param flacFile
     * @param coverImage
     */
    public static void setFlacCover(File flacFile, File coverImage) {
        try {
            // 读取FLAC文件
            AudioFile audioFile = AudioFileIO.read(flacFile);
            Tag tag = audioFile.getTag();

            // 创建Artwork对象
            Artwork artwork = Artwork.createArtworkFromFile(coverImage);

            // 设置FLAC封面
            tag.deleteArtworkField();
            tag.addField(artwork);

            // 保存修改后的FLAC文件
            audioFile.commit();

            System.out.println("FLAC封面修改成功: " + FileNameUtil.mainName(flacFile.getPath()));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 根据传入的集合, 批量添加歌曲封面
     *
     * @param flacList
     * @param coverImage
     */
    public static void setFlacCover(List<File> flacList, File coverImage) {

        AtomicInteger successCount = new AtomicInteger(0); // 记录成功修改封面的FLAC文件数量

        ExecutorService executorService = Executors.newFixedThreadPool(5); // 创建固定线程池，线程数为CPU核心数

        for (int i = 0; i < flacList.size(); i++) {
            File flacFile = flacList.get(i);
            executorService.execute(() -> {
                try {
                    // 读取FLAC文件
                    AudioFile audioFile = AudioFileIO.read(flacFile);
                    Tag tag = audioFile.getTag();

                    // 创建Artwork对象
                    Artwork artwork = Artwork.createArtworkFromFile(coverImage);

                    // 设置FLAC封面
                    tag.deleteArtworkField();
                    tag.addField(artwork);

                    // 保存修改后的FLAC文件
                    audioFile.commit();

                    int count = successCount.incrementAndGet(); // 增加成功修改封面的FLAC文件数量
                    System.out.println("FLAC封面修改成功: " + FileNameUtil.mainName(flacFile.getPath()) + ", 修改成功数量: " + count);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
        }
        executorService.shutdown();
        try {
            executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS); // 等待所有线程执行完毕
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("FLAC封面修改完成，成功修改数量: " + successCount.get());
    }


    /**
     * 根据传入的音乐文件修改歌曲标签
     *
     * @param flacFile
     */
    public static void setSongTags(File flacFile) {
        try {
            // 读取FLAC文件
            AudioFile audioFile = AudioFileIO.read(flacFile);
            Tag tag = audioFile.getTag();

            // 编辑歌曲标题、艺术家、专辑名称、专辑艺术家、作曲家、作词家和注释
            // 标题
            tag.setField(FieldKey.valueOf("TITLE"), FileNameUtil.mainName(flacFile));

            // 专辑
            File album = FileUtil.file(FileManage.getPrePath(flacFile.getPath()));
            tag.setField(FieldKey.valueOf("ALBUM"), FileNameUtil.mainName(album));

            // 艺术家
            File artist = FileUtil.file(FileManage.getPrePath(album.getPath()));
            tag.setField(FieldKey.valueOf("ARTIST"), FileNameUtil.mainName(artist));

            // 专辑艺术家
            tag.setField(FieldKey.valueOf("ALBUM_ARTIST"), "");

            // 作曲家
            tag.setField(FieldKey.valueOf("COMPOSER"), "");

            // 作词家
            tag.setField(FieldKey.valueOf("LYRICIST"), "");

            // 注释
            tag.setField(FieldKey.valueOf("COMMENT"), "");

            // 风格
            tag.setField(FieldKey.GENRE, "");
            tag.setField(FieldKey.GENRE, "");


            // 保存修改后的FLAC文件
            audioFile.commit();
            System.out.println("FLAC标签修改成功: " + FileNameUtil.mainName(flacFile.getPath()));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * 根据歌曲集合设置歌曲标签信息
     *
     * @param flacList
     */
    public static void setSongTags(List<File> flacList) {
        ExecutorService executor = Executors.newFixedThreadPool(5); // 创建一个线程池，并指定线程数上限为10
        for (File flacFile : flacList) {
            executor.submit(() -> {
                try {
                    // 读取FLAC文件
                    AudioFile audioFile = AudioFileIO.read(flacFile);
                    Tag tag = audioFile.getTag();

                    // 编辑歌曲标题、艺术家、专辑名称、专辑艺术家、作曲家、作词家和注释
                    // 标题
                    tag.setField(FieldKey.valueOf("TITLE"), FileNameUtil.mainName(flacFile));

                    // 专辑
                    File album = FileUtil.file(FileManage.getPrePath(flacFile.getPath()));
                    tag.setField(FieldKey.valueOf("ALBUM"), FileNameUtil.mainName(album));

                    // 艺术家
                    File artist = FileUtil.file(FileManage.getPrePath(album.getPath()));
                    tag.setField(FieldKey.valueOf("ARTIST"), FileNameUtil.mainName(artist));

                    // 保存修改后的FLAC文件
                    audioFile.commit();
                    System.out.println("FLAC标签修改成功: " + FileNameUtil.mainName(flacFile.getPath()));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }); // 注意这里的括号要匹配方法返回类型（这里是void）
        }
        executor.shutdown(); // 不要忘记在完成所有任务后关闭线程池，释放资源
    }
}


